package com.cloud.gateway.handler;

import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.fastjson2.JSON;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.util.HashMap;
import java.util.Map;

@Order(-1) // 必须是最低优先级（数值越小，优先级越高）
@Configuration
public class GlobalExceptionHandler implements ErrorWebExceptionHandler {

    private final ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
        if (ex instanceof BlockException) {
            // 1. 设置响应状态码和 Content-Type
            exchange.getResponse().setStatusCode(HttpStatus.TOO_MANY_REQUESTS);
            exchange.getResponse().getHeaders().setContentType(MediaType.APPLICATION_JSON);

            // 2. 构造自定义响应
            Map<String, Object> response = new HashMap<>();
            response.put("code", 429);
            response.put("message", "请求过于频繁，请稍后再试");
            response.put("path", exchange.getRequest().getPath().toString());
            response.put("timestamp", Instant.now().toString());

            try {
                // 3. 写入 JSON 响应
                byte[] bytes = objectMapper.writeValueAsBytes(response);
                DataBuffer buffer = exchange.getResponse().bufferFactory().wrap(bytes);
                return exchange.getResponse().writeWith(Mono.just(buffer));
            } catch (JsonProcessingException e) {
                return Mono.error(e);
            }
        }
        // 其他异常继续抛出
        return Mono.error(ex);
    }
}
